package com.symone.webcms.security;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.symone.webcms.common.Constants;
import com.symone.webcms.model.*;
import com.symone.webcms.model.vo.MessageVO;
import com.symone.webcms.model.vo.PermissionVO;
import com.symone.webcms.model.vo.RoleVO;
import com.symone.webcms.model.vo.UserVO;
import com.symone.webcms.service.*;
import com.symone.webcms.util.CommonUtil;
import com.xiaoleilu.hutool.lang.Validator;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

public class AuthRealm extends AuthorizingRealm {

    protected Logger logger = LoggerFactory.getLogger(AuthRealm.class);

    @Autowired
    private UserService userService;
    @Autowired
    private MenuService menuService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private LanguageService langService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private NotificationService notificationService;


    /**
     * 获取身份验证信息
     * Shiro中，最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
     *
     * @param authenticationToken 用户身份信息 token
     * @return 返回封装了用户信息的 AuthenticationInfo 实例
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("————身份认证方法————");
        //加这一步的目的是在Post请求的时候会先进认证，然后在到请求
        if (authenticationToken.getPrincipal() == null) {
            return null;
        }
        //获取用户信息
        String name = authenticationToken.getPrincipal().toString();
        UserVO user = userService.findUserByName(name);
        if (user == null) {
            //这里返回后会报出对应异常
            return null;
        } else {
            if(user.getRoleList().isEmpty()){
                return null;
            }
            //这里验证authenticationToken和simpleAuthenticationInfo的信息
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword().toString(), getName());

            Set<PermissionVO> permissions = new HashSet<>();
            for (RoleVO role : user.getRoleList()) {
                if(role.getId() == 1 ){
                    permissions.addAll(roleService.fetchAllPermissions());
                }else {
                    permissions.addAll(Arrays.asList(role.getPermissions()));
                }
            }
            List<Menu> allMenus = menuService.selectList(new EntityWrapper<Menu>().eq("deleted",0).orderBy("pid").orderBy("sorting"));
            List<Menu> userMenus = new ArrayList<>();
            for (Menu menu : allMenus) {
                for (PermissionVO permission : permissions) {
                    if (menu != null && permission != null && menu.getShiroCode() != null && permission.getCode() != null && menu.getShiroCode().equals(permission.getCode())) {
                        userMenus.add(menu);
                    }
                }
            }

            //将用户信息放入session中
            Session session = SecurityUtils.getSubject().getSession();
            session.setAttribute(Constants.CURRENT_USER_SESSION, user);
            session.setAttribute(Constants.CURRENT_USER_ROLES, user.getRoleList());
            session.setAttribute(Constants.CURRENT_PERMISSION_SESSION, permissions);
            session.setAttribute(Constants.CURRENT_MENU_LIST, CommonUtil.list2Tree(userMenus));

            List<MessageVO> messages = messageService.getMessageRecieveBox(user.getId(),0);
            session.setAttribute(Constants.SYS_MESSAGE_LIST, messages);
            List<Notification> notifications = notificationService.selectList(new EntityWrapper<Notification>().eq("is_read",0).and().eq("user_id",user.getId()));
            session.setAttribute(Constants.SYS_NOTIFICATION_LIST, notifications);

            setSessionLanguageList();
            return simpleAuthenticationInfo;
        }
    }

    /**
     * 获取授权信息
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("————权限认证————");
        Session session = SecurityUtils.getSubject().getSession();
        UserVO user = (UserVO) session.getAttribute(Constants.CURRENT_USER_SESSION);
        Set<PermissionVO> permissions = (Set<PermissionVO>) session.getAttribute(Constants.CURRENT_PERMISSION_SESSION);
        logger.info("permission的值为:" + permissions);

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        for(PermissionVO perm : permissions) {
            if (perm != null && perm.getCode() != null && !Validator.isEmpty(perm.getCode())) {
                info.addStringPermission(perm.getCode());
            }
        }
        for(RoleVO role : user.getRoleList()){
            info.addRole(role.getCode());
        }

        return info;
    }

    /**
     * 获取语言列表和默认语言并设置到Session中
     */
    private void setSessionLanguageList() {
        Object languageObj = SecurityUtils.getSubject().getSession().getAttribute(Constants.SYS_LANGUAGE_LIST);
        Language current_language = (Language) SecurityUtils.getSubject().getSession().getAttribute(Constants.CURRENT_LANGUAGE);
        if ((languageObj == null) || (languageObj instanceof List && ((List) languageObj).size() > 0)) {
            List<Language> languages = langService.selectList(new EntityWrapper<Language>().eq("deleted",0));
            if (current_language == null) {
                for (Language language : languages) {
                    if(language.getIsDefault() == 1){
                        SecurityUtils.getSubject().getSession().setAttribute(Constants.CURRENT_LANGUAGE, language);
                    }
                }
            }
            SecurityUtils.getSubject().getSession().setAttribute(Constants.SYS_LANGUAGE_LIST, languages);
        }
    }

}